home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * All Input is assumed to be going to RAM (no longer, ROM works, too.)
- * All Output is assumed to be coming from either RAM or ROM
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #ifdef VMS
- #include <unixio.h>
- #include <file.h>
- #else
- #include <fcntl.h>
- #ifndef AMIGA
- #include <unistd.h>
- #endif
- #endif
-
- #ifdef DJGPP
- #include "djgpp.h"
- #endif
-
- static char *rcsid = "$Id: sio.c,v 1.8 1997/09/30 thor,david Exp $";
-
- #define FALSE 0
- #define TRUE 1
-
- #include "atari.h"
- #include "cpu.h"
- #include "sio.h"
- #include "pokey11.h"
- #include "mem.h"
-
- #define MAGIC1 0x96
- #define MAGIC2 0x02
-
- struct ATR_Header
- {
- unsigned char magic1;
- unsigned char magic2;
- unsigned char seccountlo;
- unsigned char seccounthi;
- unsigned char secsizelo;
- unsigned char secsizehi;
- unsigned char hiseccountlo;
- unsigned char hiseccounthi;
- unsigned char gash[8];
- };
-
- typedef enum Format { XFD, ATR } Format;
-
- static Format format[MAX_DRIVES];
- static int disk[MAX_DRIVES] = { -1, -1, -1, -1, -1, -1, -1, -1 };
- static int sectorcount[MAX_DRIVES];
- static int sectorsize[MAX_DRIVES];
-
- static enum DriveStatus
- {
- Off,
- NoDisk,
- ReadOnly,
- ReadWrite
- } drive_status[MAX_DRIVES];
-
- char sio_filename[MAX_DRIVES][FILENAME_LEN];
-
- /* Serial I/O emulation support */
- UBYTE CommandFrame[6];
- int CommandIndex=0;
- UBYTE DataBuffer[256+3];
- char sio_status[256];
- int DataIndex=0;
- int TransferStatus=0;
- int ExpectedBytes=0;
-
-
- void SIO_Initialise (int *argc, char *argv[])
- {
- int i;
-
- for (i=0;i<MAX_DRIVES;i++)
- strcpy (sio_filename[i], "Empty");
-
- TransferStatus = SIO_NoFrame;
- }
-
- int SIO_Mount (int diskno, char *filename)
- {
- struct ATR_Header header;
-
- int fd;
-
- drive_status[diskno-1] = ReadWrite;
- strcpy (sio_filename[diskno-1], "Empty");
-
- fd = open (filename, O_RDWR, 0777);
- if (fd == -1)
- {
- fd = open (filename, O_RDONLY, 0777);
- drive_status[diskno-1] = ReadOnly;
- }
-
- if (fd)
- {
- int status;
-
- status = read (fd, &header, sizeof(struct ATR_Header));
- if (status == -1)
- {
- close (fd);
- disk[diskno-1] = -1;
- return FALSE;
- }
-
- strcpy (sio_filename[diskno-1], filename);
-
- if ((header.magic1 == MAGIC1) && (header.magic2 == MAGIC2))
- {
- sectorcount[diskno-1] = header.hiseccounthi << 24 |
- header.hiseccountlo << 16 |
- header.seccounthi << 8 |
- header.seccountlo;
-
- sectorsize[diskno-1] = header.secsizehi << 8 |
- header.secsizelo;
-
- sectorcount[diskno-1] /= 8;
- if (sectorsize[diskno-1] == 256)
- {
- sectorcount[diskno-1] += 3; /* Compensate for first 3 sectors */
- sectorcount[diskno-1] /= 2;
- }
-
- #ifdef DEBUG
- printf ("ATR: sectorcount = %d, sectorsize = %d\n",
- sectorcount[diskno-1],
- sectorsize[diskno-1]);
- #endif
-
- format[diskno-1] = ATR;
- }
- else
- {
- format[diskno-1] = XFD;
- sectorcount[diskno-1]=lseek(fd,0,SEEK_END)/128;
- lseek(fd,0,SEEK_SET);
- sectorsize[diskno-1]=128;
- }
- }
- else
- {
- drive_status[diskno-1] = NoDisk;
- }
-
- disk[diskno-1] = fd;
-
- return (disk[diskno-1] != -1) ? TRUE : FALSE;
- }
-
- void SIO_Dismount (int diskno)
- {
- if (disk[diskno-1] != -1)
- {
- close (disk[diskno-1]);
- disk[diskno-1] = -1;
- drive_status[diskno-1] = NoDisk;
- strcpy (sio_filename[diskno-1], "Empty");
- }
- }
-
- void SIO_DisableDrive (int diskno)
- {
- drive_status[diskno-1] = Off;
- strcpy (sio_filename[diskno-1], "Off");
- }
-
- void SizeOfSector(UBYTE unit,int sector,int *sz,ULONG *ofs)
- {
- int size=128;
- ULONG offset=0;
-
- switch (format[unit]) {
- case XFD :
- offset = (sector-1)*128;
- break;
- case ATR :
- if (sector < 4) {
- offset = (sector-1) * 128 + 16;
- } else {
- offset = (sector - 1) * sectorsize[unit] + 16;
- size = sectorsize[unit];
- }
- /*
- offset = 3*128 + (sector-4) * sectorsize[unit] + 16;
- */
- break;
- default :
- printf ("Fatal Error in atari_sio.c\n");
- Atari800_Exit (FALSE, 1);
- }
-
- if (sz)
- *sz = size;
-
- if (ofs)
- *ofs = offset;
- }
-
- int SeekSector(int unit,int sector)
- {
- ULONG offset;
- int size;
-
- sprintf (sio_status, "%d: %d", unit+1, sector);
- SizeOfSector(unit,sector,&size,&offset);
- /* printf("Sector %x,Offset: %x\n",sector,offset); */
- lseek(disk[unit], offset, SEEK_SET);
-
- return size;
- }
-
-
- /* Unit counts from zero up */
- int ReadSector(int unit,int sector,UBYTE *buffer)
- {
- int size;
-
- if (drive_status[unit] != Off) {
- if (disk[unit] != -1) {
- if (sector<=sectorcount[unit]) {
- size = SeekSector (unit, sector);
- read (disk[unit], buffer, size);
- return 'C';
- } else return 'E';
- } else return 'N';
- } else return 0;
- }
-
- int WriteSector(int unit,int sector,UBYTE *buffer)
- {
- int size;
-
- if (drive_status[unit] != Off) {
- if (disk[unit] != -1) {
- if (drive_status[unit] == ReadWrite) {
- if (sector<=sectorcount[unit]) {
- size = SeekSector (unit, sector);
- write (disk[unit], buffer, size);
- return 'C';
- } else return 'E';
- } else return 'E';
- } else return 'N';
- } else return 0;
- }
-
- int FormatSingle(int unit,UBYTE *buffer)
- {
- int i;
-
- if (drive_status[unit] != Off) {
- if (disk[unit] != -1) {
- if (drive_status[unit] == ReadWrite) {
- sectorcount[unit] = 720;
- sectorsize[unit] = 128;
- format[unit] = XFD;
- SeekSector(unit,1);
- memset(buffer,0,128);
- for(i=1;i<=720;i++)
- write (disk[unit],buffer,128);
- memset(buffer,0xff,128);
- return 'C';
- } else return 'E';
- } else return 'N';
- } else return 0;
- }
-
- int FormatEnhanced(int unit,UBYTE *buffer)
- {
- int i;
-
- if (drive_status[unit] != Off) {
- if (disk[unit] != -1) {
- if (drive_status[unit] == ReadWrite) {
- sectorcount[unit] = 1040;
- sectorsize[unit] = 128;
- format[unit] = XFD;
- SeekSector(unit,1);
- memset(buffer,0,128);
- for(i=1;i<=1040;i++)
- write (disk[unit],buffer,128);
- memset(buffer,0xff,128);
- return 'C';
- } else return 'E';
- } else return 'N';
- } else return 0;
- }
-
- int WriteStatusBlock(int unit,UBYTE *buffer)
- {
-
- if (drive_status[unit] != Off) {
- /* We only care about the density right here. Setting everything else
- right here seems to be non-sense */
- if (format[unit] == ATR) {
- if (buffer[5]==8) {
- sectorsize[unit] = 256;
- } else {
- sectorsize[unit] = 128;
- }
- sectorcount[unit] = 720;
- return 'C';
- } else return 'E';
- } else return 0;
- }
-
- int ReadStatusBlock(int unit,UBYTE *buffer)
- {
- int size;
-
- if (drive_status[unit] != Off) {
- SizeOfSector(unit,0x168,&size,NULL);
- buffer[0] = 40; /* # of tracks */
- buffer[1] = 1; /* step rate. No idea what this means */
- buffer[2] = 0; /* sectors per track. HI byte */
- buffer[3] = 18; /* sectors per track. LO byte */
- buffer[4] = 1; /* # of heads */
- if (size==128) {
- buffer[5] = 4; /* density */
- buffer[6] = 0; /* HI bytes per sector */
- buffer[7] = 128; /* LO bytes per sector */
- } else {
- buffer[5] = 8; /* double density */
- buffer[6] = 1; /* HI bytes per sector */
- buffer[7] = 0; /* LO bytes per sector */
- }
- buffer[8] = 1; /* drive is online */
- buffer[9] = 192; /* transfer speed. Whatever this means */
- return 'C';
- } else return 0;
- }
-
- /*
- Status Request from Atari 400/800 Technical Reference Notes
-
- DVSTAT + 0 Command Status
- DVSTAT + 1 Hardware Status
- DVSTAT + 2 Timeout
- DVSTAT + 3 Unused
-
- Command Status Bits
-
- Bit 0 = 1 indicates an invalid command frame was received
- Bit 1 = 1 indicates an invalid data frame was received
- Bit 2 = 1 indicates that a PUT operation was unsuccessful
- Bit 3 = 1 indicates that the diskete is write protected
- Bit 4 = 1 indicates active/standby
-
- plus
-
- Bit 5 = 1 indicates double density
- Bit 7 = 1 indicates duel density disk (1050 format)
- */
- int DriveStatus(int unit,UBYTE *buffer)
- {
- if (drive_status[unit] != Off) {
- if (drive_status[unit] == ReadWrite) {
- buffer[0] = (sectorsize[unit] == 256)?(32+16):(16);
- buffer[1] = (disk[unit] != -1)?(128):(0);
- } else {
- buffer[0] = (sectorsize[unit] == 256)?(32):(0);
- buffer[1] = (disk[unit] != -1)?(192):(64);
- }
- if (sectorcount[unit]==1040) buffer[0] |= 128;
- buffer[2] = 1;
- buffer[3] = 0;
- return 'C';
- } else return 0;
- }
-
-
- void SIO (void)
- {
- int sector = DPeek(0x30a);
- UBYTE unit = Peek(0x301) - 1;
- UBYTE result=0x00;
- ATPtr data = DPeek(0x304);
- int length = DPeek(0x308);
- int realsize;
- int cmd = Peek(0x302);
-
- #ifdef MOTIF
- Atari_Set_LED(1);
- #endif
-
- /*
- printf("SIO: Unit %x,Sector %x,Data %x,Length %x,CMD %x\n",unit,sector,data,length,cmd);
- */
-
- if (Peek(0x300) == 0x31) switch (cmd) {
- case 0x4e : /* Read Status Block */
- if (12 == length) {
- result = ReadStatusBlock(unit,DataBuffer);
- if (result == 'C')
- CopyToMem(DataBuffer,data,12);
- } else result = 'E';
- break;
- case 0x4f : /* Write Status Block */
- if (12 == length) {
- CopyFromMem(data,DataBuffer,12);
- result = WriteStatusBlock(unit,DataBuffer);
- } else result = 'E';
- break;
- case 0x50 : /* Write */
- case 0x57 :
- SizeOfSector(unit,sector,&realsize,NULL);
- if (realsize == length) {
- CopyFromMem(data,DataBuffer,realsize);
- result = WriteSector(unit,sector,DataBuffer);
- } else result = 'E';
- break;
- case 0x52: /* Read */
- SizeOfSector(unit,sector,&realsize,NULL);
- if (realsize == length) {
- result = ReadSector(unit,sector,DataBuffer);
- if (result == 'C')
- CopyToMem(DataBuffer,data,realsize);
- }
- else result = 'E';
- break;
- case 0x53: /* Status */
- if (4 == length) {
- result = DriveStatus(unit,DataBuffer);
- CopyToMem(DataBuffer,data,4);
- } else result = 'E';
- break;
- case 0x21 : /* Single Density Format */
- if (length == 128) {
- result = FormatSingle(unit,DataBuffer);
- if (result == 'C')
- CopyToMem(DataBuffer,data,realsize);
- } else result = 'E';
- break;
- case 0x22 : /* Enhanced Density Format */
- if (length == 128) {
- result = FormatEnhanced(unit,DataBuffer);
- if (result == 'C')
- CopyToMem(DataBuffer,data,realsize);
- } else result = 'E';
- break;
- case 0x66 : /* US Doubler Format - I think! */
- result = 'A'; /* Not yet supported... to be done later... */
- break;
- default:
- result = 'N';
- }
-
- switch(result) {
- case 0x00: /* Device disabled, generate timeout */
- regY = 138;
- SetN;
- break;
- case 'A': /* Device acknoledge */
- case 'C': /* Operation complete */
- regY = 1;
- ClrN;
- break;
- case 'N': /* Device NAK */
- regY = 144;
- SetN;
- break;
- case 'E': /* Device error */
- default:
- regY = 146;
- SetN;
- break;
- }
-
- Poke(0x0303,regY);
-
- #ifdef MOTIF
- Atari_Set_LED(0);
- #endif
-
- }
-
- void SIO_Initialize(void)
- {
- TransferStatus = SIO_NoFrame;
- }
-
-
- UBYTE ChkSum(UBYTE *buffer,UWORD length)
- {
- int i;
- int checksum=0;
-
- for (i=0;i<length;i++,buffer++) {
- checksum += *buffer;
- while (checksum > 255)
- checksum -= 255;
- }
-
- return checksum;
- }
-
- void Command_Frame (void)
- {
- int unit;
- int result='A';
- int sector;
- int realsize;
-
-
- sector = CommandFrame[2] | (((UWORD)(CommandFrame[3]))<<8);
- unit = CommandFrame[0]-'1';
- if (unit>8) { /* UBYTE - range ! */
- printf ("Unknown command frame: %02x %02x %02x %02x %02x\n",
- CommandFrame[0], CommandFrame[1], CommandFrame[2],
- CommandFrame[3], CommandFrame[4]);
- result = 0;
- } else switch (CommandFrame[1]) {
- case 0x4e : /* Read Status */
- DataBuffer[0] = ReadStatusBlock(unit,DataBuffer+1);
- DataBuffer[13] = ChkSum(DataBuffer+1,12);
- DataIndex = 0;
- ExpectedBytes = 14;
- TransferStatus = SIO_ReadFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- break;
- case 0x4f :
- ExpectedBytes = 13;
- DataIndex = 0;
- TransferStatus = SIO_WriteFrame;
- break;
- case 0x50 : /* Write */
- case 0x57 :
- SizeOfSector(unit,sector,&realsize,NULL);
- ExpectedBytes = realsize+1;
- DataIndex = 0;
- TransferStatus = SIO_WriteFrame;
- break;
- case 0x52: /* Read */
- SizeOfSector(unit,sector,&realsize,NULL);
- DataBuffer[0] = ReadSector(unit,sector,DataBuffer+1);
- DataBuffer[1+realsize] = ChkSum(DataBuffer+1,realsize);
- DataIndex = 0;
- ExpectedBytes = 2+realsize;
- TransferStatus = SIO_ReadFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- break;
- case 0x53: /* Status */
- DataBuffer[0] = DriveStatus(unit,DataBuffer+1);
- DataBuffer[1+4] = ChkSum(DataBuffer+1,4);
- DataIndex = 0;
- ExpectedBytes = 6;
- TransferStatus = SIO_ReadFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- break;
- case 0x21 : /* Single Density Format */
- DataBuffer[0] = FormatSingle(unit,DataBuffer+1);
- DataBuffer[1+128] = ChkSum(DataBuffer+1,128);
- DataIndex = 0;
- ExpectedBytes = 2+128;
- TransferStatus = SIO_FormatFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- break;
- case 0x22 : /* Duel Density Format */
- DataBuffer[0] = FormatEnhanced(unit,DataBuffer+1);
- DataBuffer[1+128] = ChkSum(DataBuffer+1,128);
- DataIndex = 0;
- ExpectedBytes = 2+128;
- TransferStatus = SIO_FormatFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- break;
- case 0x66 : /* US Doubler Format - I think! */
- result = 'A'; /* Not yet supported... to be done later... */
- break;
- default :
- printf ("Command frame: %02x %02x %02x %02x %02x\n",
- CommandFrame[0], CommandFrame[1], CommandFrame[2],
- CommandFrame[3], CommandFrame[4]);
- break;
- result = 0;
- }
-
- if (result == 0)
- TransferStatus = SIO_NoFrame;
- }
-
-
- /* Enable/disable the command frame */
- void SwitchCommandFrame(int onoff)
- {
-
- if (onoff) { /* Enabled */
- if (TransferStatus != SIO_NoFrame)
- printf("Unexpected command frame %x.\n",TransferStatus);
- CommandIndex = 0;
- DataIndex = 0;
- ExpectedBytes = 5;
- TransferStatus = SIO_CommandFrame;
- #ifdef MOTIF
- Atari_Set_LED(1);
- #endif
- /* printf("Command frame expecting.\n"); */
- } else {
- if (TransferStatus!=SIO_StatusRead && TransferStatus!=SIO_NoFrame &&
- TransferStatus!=SIO_ReadFrame) {
- if (!(TransferStatus==SIO_CommandFrame && CommandIndex==0))
- printf("Command frame %02x unfinished.\n",TransferStatus);
- TransferStatus = SIO_NoFrame;
- }
- CommandIndex = 0;
- }
- }
-
- UBYTE WriteSectorBack(void)
- {
- UWORD sector;
- UBYTE unit;
- UBYTE result;
-
- sector = CommandFrame[2] | (((UWORD)(CommandFrame[3]))<<8);
- unit = CommandFrame[0]-'1';
- if (unit>8) { /* UBYTE range ! */
- result = 0;
- } else switch (CommandFrame[1]) {
- case 0x4f : /* Write Status Block */
- result=WriteStatusBlock(unit,DataBuffer);
- break;
- case 0x50 : /* Write */
- case 0x57 :
- result=WriteSector(unit,sector,DataBuffer);
- break;
- default:
- result = 'E';
- }
-
- return result;
- }
-
- /* Put a byte that comes out of POKEY. So get it here... */
- void SIO_PutByte(int byte)
- {
- UBYTE sum,result;
-
- switch(TransferStatus) {
- case SIO_CommandFrame:
- if (CommandIndex < ExpectedBytes) {
- CommandFrame[CommandIndex++] = byte;
- if (CommandIndex >= ExpectedBytes) {
- /* printf("%x\n",CommandFrame[0]); */
- if (((CommandFrame[0]>=0x31) && (CommandFrame[0]<=0x38))) {
- TransferStatus = SIO_StatusRead;
- /* printf("Command frame done.\n"); */
- DELAYED_SERIN_IRQ += SERIN_INTERVAL + ACK_INTERVAL;
- } else TransferStatus = SIO_NoFrame;
- }
- } else {
- printf("Invalid command frame!\n");
- TransferStatus = SIO_NoFrame;
- }
- break;
- case SIO_WriteFrame: /* Expect data */
- if (DataIndex < ExpectedBytes) {
- DataBuffer[DataIndex++] = byte;
- if (DataIndex >= ExpectedBytes) {
- sum = ChkSum(DataBuffer,ExpectedBytes - 1);
- if (sum == DataBuffer[ExpectedBytes - 1]) {
- result = WriteSectorBack();
- if (result) {
- DataBuffer[0] = 'A';
- DataBuffer[1] = result;
- DataIndex = 0;
- ExpectedBytes = 2;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL + ACK_INTERVAL;
- TransferStatus = SIO_FinalStatus;
- /* printf("Sector written, result= %x.\n",result); */
- } else TransferStatus = SIO_NoFrame;
- } else {
- DataBuffer[0] = 'E';
- DataIndex = 0;
- ExpectedBytes = 1;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL + ACK_INTERVAL;
- TransferStatus = SIO_FinalStatus;
- }
- }
- } else {
- printf("Invalid data frame!\n");
- }
- break;
- default:
- printf("Unexpected data output :%x\n",byte);
- }
- DELAYED_SEROUT_IRQ += SEROUT_INTERVAL;
-
- }
-
- /* Get a byte from the floppy to the pokey. */
-
- int SIO_GetByte(void)
- {
- int byte = 0;
-
- switch(TransferStatus) {
- case SIO_StatusRead:
- byte = 'A'; /* Command acknoledged */
- /* printf("Command status read\n"); */
- Command_Frame(); /* Handle now the command */
- break;
- case SIO_FormatFrame:
- TransferStatus = SIO_ReadFrame;
- DELAYED_SERIN_IRQ += SERIN_INTERVAL<<3;
- case SIO_ReadFrame:
- if (DataIndex < ExpectedBytes) {
- byte=DataBuffer[DataIndex++];
- if (DataIndex >= ExpectedBytes) {
- TransferStatus = SIO_NoFrame;
- #ifdef MOTIF
- Atari_Set_LED(0);
- #endif
- /* printf("Transfer complete.\n"); */
- } else {
- DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- }
- } else {
- printf("Invalid read frame!\n");
- TransferStatus = SIO_NoFrame;
- }
- break;
- case SIO_FinalStatus:
- if (DataIndex < ExpectedBytes) {
- byte=DataBuffer[DataIndex++];
- if (DataIndex >= ExpectedBytes) {
- TransferStatus = SIO_NoFrame;
- #ifndef BASIC
- Atari_Set_LED(0);
- #endif
- /* printf("Write complete.\n"); */
- } else {
- if (DataIndex == 0)
- DELAYED_SERIN_IRQ += SERIN_INTERVAL+ACK_INTERVAL;
- else DELAYED_SERIN_IRQ += SERIN_INTERVAL;
- }
- } else {
- printf("Invalid read frame!\n");
- #ifndef BASIC
- Atari_Set_LED(0);
- #endif
- TransferStatus = SIO_NoFrame;
- }
- break;
- default:
- printf("Unexpected data reading!\n");
- break;
- }
-
- return byte;
- }
-